package com.xiaouyudeguang.common.reader;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.xiaouyudeguang.common.model.XMindModel;
import com.xiaouyudeguang.common.utils.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.ArchiveException;
import org.apache.commons.compress.archivers.examples.Expander;
import org.xmind.core.*;
import org.xmind.core.io.ByteArrayStorage;

import java.io.*;
import java.util.*;

@Slf4j
public class XMindReader {

    public static final String CONTENT_JSON = "content.json";
    //当前文件位置
    private static final String CURRENT_PATH = System.getProperty("user.dir");

    /**
     * 想读XMind，读就完了
     */
    public static Object readXMind(File file) {
        String res = null;
        Object contents = null;
        try {
            res = extract(file);
            if (isXMindNetwork(res, file)) {
                contents = (getXMindNetworkContent(file, res));
            } else {
                contents = getXMind8Content(file);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 删除生成的文件夹
            if (res != null) {
                File dir = new File(res);
                deleteDir(dir);
            }
            // 删除零时文件
//            if (file != null) {
//                file.delete();
//            }
        }
        return contents;
    }

    /**
     * 填充节点
     *
     * @param iTopic
     * @return 一个节点
     */
    public static XMindModel fillNode(ITopic iTopic) {
        XMindModel newNode = new XMindModel();
        try {
            //内容
            newNode.setContent(iTopic.getTitleText());
            //链接
            newNode.setLink(iTopic.getHyperlink());
            //标签
            Set<String> labels = iTopic.getLabels();
            if (labels != null && labels.size() != 0) {
                newNode.setLabels(labels);
            }
            //图片
            //IImage image = iTopic.getImage();
            //newNode.setIImage(image.getSource());
            //批注
            //newNode.setMarkers();
            //备注
            IPlainNotesContent content = (IPlainNotesContent) iTopic.getNotes().getContent(INotes.PLAIN);
            if (content != null) {
                newNode.setComment(content.getTextContent());
            }
        } catch (Exception e) {
            log.error("*****填充node出错*****");
            e.printStackTrace();
        }

        return newNode;
    }

    /**
     * 填充节点
     *
     * @param attachedObject
     * @return 一个节点
     */
    public static XMindModel fillNodeNetwork(JsonNode attachedObject) {
        XMindModel newNode = new XMindModel();
        try {
            JsonNode notes = attachedObject.get("notes");
            if (notes != null) {
                JsonNode plain = notes.get("plain");
                if (plain != null) {
                    newNode.setComment(plain.get("content").asText());
                }
            }
            newNode.setContent(attachedObject.get("title").asText());
            newNode.setLabels(Collections.singleton(attachedObject.get("labels").asText()));
            newNode.setMarkers(Collections.singleton(attachedObject.get("markers").asText()));
        } catch (Exception e) {
            log.error("*****填充nodeNetwork出错*****");
            e.printStackTrace();
        }
        return newNode;
    }

    /**
     * 建立文件内容树
     *
     * @param file
     * @return json串
     */
    public static Object getXMind8Content(File file) {
        //初始化builder
        IWorkbookBuilder builder = Core.getWorkbookBuilder();
        IWorkbook workbook = null;
        try {
            //打开XMind文件
            workbook = builder.loadFromFile(file, new ByteArrayStorage(), null);
        } catch (IOException | CoreException e) {
            e.printStackTrace();
        }

        if (workbook == null) {
            return "文件为空或格式不匹配";
        }

        //获取主Sheet
        ISheet defSheet = workbook.getPrimarySheet();
        //获取根Topic
        ITopic rootTopic = defSheet.getRootTopic();
        //遍历树
        Queue<Object> iTopicQueue = new LinkedList<>();
        iTopicQueue.add(rootTopic);
        //新树
        XMindModel xMindNodeRoot = new XMindModel();
        xMindNodeRoot.setContent(rootTopic.getTitleText());
        xMindNodeRoot.setLevel(1);
        iTopicQueue.add(xMindNodeRoot);
        while (!iTopicQueue.isEmpty()) {
            ITopic oldTreeNode = (ITopic) iTopicQueue.poll();
            XMindModel treeNode = (XMindModel) iTopicQueue.poll();
            if (treeNode == null) {
                return null;
            }
            Integer level = treeNode.getLevel() + 1;
            List<XMindModel> xMindModels = new ArrayList<>();
            for (ITopic oneChild : oldTreeNode.getAllChildren()) {
                XMindModel newNode = XMindReader.fillNode(oneChild);
                newNode.setLevel(level);
                xMindModels.add(newNode);
                iTopicQueue.add(oneChild);
                iTopicQueue.add(newNode);
            }
            treeNode.setChildren(xMindModels);
        }
        return JsonObject.toJson(xMindNodeRoot);
    }

    /**
     * 网上版本 建立文件内容树
     *
     * @param file
     * @return json串
     */
    public static Object getXMindNetworkContent(File file, String extractFileDir) throws IOException {
        List<String> keys = new ArrayList<>();
        keys.add(CONTENT_JSON);
        Map<String, String> map = getContents(keys, file, extractFileDir);
        String content = map.get(CONTENT_JSON);
        ArrayNode jsonArray = (ArrayNode) JsonObject.readTree(content);
        JsonNode jsonObject = jsonArray.get(0);
        JsonNode rootTopic = jsonObject.get("rootTopic");

        //遍历树
        Queue<Object> iTopicQueue = new LinkedList<>();
        iTopicQueue.add(rootTopic);
        //新树
        XMindModel xMindNodeRoot = new XMindModel();
        xMindNodeRoot.setContent(rootTopic.get("title").asText());
        xMindNodeRoot.setLevel(1);
        iTopicQueue.add(xMindNodeRoot);
        while (!iTopicQueue.isEmpty()) {
            JsonNode oldTreeNode = (JsonNode) iTopicQueue.poll();
            XMindModel treeNode = (XMindModel) iTopicQueue.poll();
            if (treeNode == null) {
                return null;
            }
            Integer level = treeNode.getLevel() + 1;
            List<XMindModel> xMindModels = new ArrayList<>();
            JsonNode children = oldTreeNode.get("children");
            if (children == null) {
                continue;
            }
            ArrayNode attachedArray = children.withArray("attached");
            if (attachedArray == null) {
                continue;
            }
            for (JsonNode attached : attachedArray) {
                XMindModel newNode = XMindReader.fillNodeNetwork(attached);
                newNode.setLevel(level);
                xMindModels.add(newNode);
                iTopicQueue.add(attached);
                iTopicQueue.add(newNode);
            }
            treeNode.setChildren(xMindModels);
        }
        return JsonObject.toJson(xMindNodeRoot);
    }

    /**
     * 判断是否有CONTENT_JSON文件
     */
    private static boolean isXMindNetwork(String res, File file) {
        // 解压
        File parent = new File(res);
        if (parent.isDirectory()) {
            String[] files = parent.list(new FileFilter());
            for (int i = 0; i < Objects.requireNonNull(files).length; i++) {
                if (files[i].equals(CONTENT_JSON)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 返回解压后的文件夹名字
     */
    public static String extract(File file) throws IOException, ArchiveException {
        Expander expander = new Expander();
        String destFileName = CURRENT_PATH + File.separator + "XMind" + System.currentTimeMillis();
        expander.expand(file, new File(destFileName));
        return destFileName;
    }

    /**
     * 找CONTENT_JSON文件
     */
    public static Map<String, String> getContents(List<String> subFileNames, File file, String extractFileDir) throws IOException {
        String destFilePath = extractFileDir;
        Map<String, String> map = new HashMap<>(16);
        File destFile = new File(destFilePath);
        if (destFile.isDirectory()) {
            String[] res = destFile.list(new FileFilter());
            for (int i = 0; i < Objects.requireNonNull(res).length; i++) {
                if (subFileNames.contains(res[i])) {
                    String s = destFilePath + File.separator + res[i];
                    String content = getFileContent(s);
                    map.put(res[i], content);
                }
            }
        }
        return map;
    }

    /**
     * 返回CONTENT_JSON文件内容
     */
    public static String getFileContent(String fileName) throws IOException {
        File file;
        try {
            file = new File(fileName);
        } catch (Exception e) {
            throw new RuntimeException("找不到该文件");
        }
        FileReader fileReader = new FileReader(file);
        BufferedReader bufferedReder = new BufferedReader(fileReader);
        StringBuilder stringBuffer = new StringBuilder();
        while (bufferedReder.ready()) {
            stringBuffer.append(bufferedReder.readLine());
        }
        // 打开的文件需关闭，在unix下可以删除，否则在windows下不能删除（file.delete())
        bufferedReder.close();
        fileReader.close();
        return stringBuffer.toString();
    }

    /**
     * 过滤器
     */
    static class FileFilter implements FilenameFilter {
        @Override
        public boolean accept(File dir, String name) {
            // String的 endsWith(String str)方法 筛选出以str结尾的字符串
            if (name.endsWith(".xml") || name.endsWith(".json")) {
                return true;
            }
            return false;
        }
    }

    /**
     * 删除生成的文件夹
     */
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            // 递归删除目录中的子目录下
            for (int i = 0; i < children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }
}